package com.leilei.autoconfigure;

import com.leilei.support.redis.SpringRedisProvider;
import com.leilei.support.redis.SpringRedisPubSubPolicy;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author lei
 * @create 2022-05-10 14:51
 * @desc j2Cache配置类 使其支持spring-boot yml文件，无需再额外配置j2cache.properties
 **/
@ConfigurationProperties(prefix = "j2cache")
public class J2CacheConfigProperties {

    /**
     * 是否开启spring cache缓存,注意:开启后需要添加spring.cache.type=GENERIC,将缓存类型设置为GENERIC
     */
    private Boolean openSpringCache = false;

    /**
     * 缓存清除模式，
     * <ul>
     * <li>active:主动清除，二级缓存过期主动通知各节点清除，优点在于所有节点可以同时收到缓存清除</li>
     * <li>passive:被动清除，一级缓存过期进行通知各节点清除一二级缓存，</li>
     * <li> blend:两种模式一起运作，对于各个节点缓存准确以及及时性要求高的可以使用，正常用前两种模式中一个就可</li>
     * </ul>
     */
    private String cacheCleanMode = "passive";

    /**
     * 是否允许缓存空值,默认:false
     */
    private boolean allowNullValues = false;

    /**
     * 是否开启二级缓存
     */
    private boolean l2CacheOpen = true;

    /**
     * 缓存变更广播方式（jgroups | redis | lettuce | rabbitmq | rocketmq | none | 自定义class）<br/>
     * 注：默认SpringBoot Redis自定义实现SpringRedisPubSubPolicy
     */
    private String broadcast = SpringRedisPubSubPolicy.class.getName();

    /**
     * L1级缓存配置
     */
    private MyLevel1Config l1 = new MyLevel1Config();
    /**
     * L2缓存配置
     */
    private MyLevel2Config l2 = new MyLevel2Config();
    /**
     * 兼容原J2Cache属性配置
     * j2ache.properties
     */
    private Properties properties = new Properties();


    /**
     * 一级缓存配置类
     */
    public static class MyLevel1Config {
        /**
         * L1 缓存provider名称（caffeine | ehcache | ehcache3）
         */
        private String providerClass = "caffeine";
        /**
         * Caffeine缓存配置 设置region一级缓存大小过期属性
         */
        private CaffeineConfig caffeine = new CaffeineConfig();


        public String getProviderClass() {
            return providerClass;
        }

        public void setProviderClass(String providerClass) {
            this.providerClass = providerClass;
        }

        public CaffeineConfig getCaffeine() {
            return caffeine;
        }

        public void setCaffeine(CaffeineConfig caffeine) {
            this.caffeine = caffeine;
        }
    }

    /**
     * Caffeine配置
     */
    public static class CaffeineConfig {
        /**
         * Caffeine缓存region配置<br/>
         * 格式如下（目前仅支持配置设置cache中最多缓存对象数量及过期时间）：
         * [regionName] = size, xxxx[s|m|h|d]
         */
        private Map<String, String> region = new HashMap<String, String>() {
            {
                put("default", "1000,3h");
            }
        };

        public Map<String, String> getRegion() {
            return region;
        }

        public void setRegion(Map<String, String> region) {
            this.region = region;
        }
    }

    /**
     * 二级缓存配置类
     */
    public static class MyLevel2Config {
        /**
         * 二级缓存provider类名（redis | lettuce | readonly-redis | memcached）<br/>
         * 与配置 j2cache.L2.provider_class  属性一致
         */
        private String providerClass = SpringRedisProvider.class.getName();
        /**
         * 一二级缓存序列化方式
         */
        private String serialization = "fastjson";
        /**
         * 二级缓存配置属性前缀
         * 可不设置
         */
        private String l2CacheSection;

        /**
         * 是否启用同步一级缓存的Time-To-Live超时时间到Redis
         * true启用，一二级缓存失效时间一致
         * false不启用，一级缓存按设置失效,二级缓存永不失效
         */
        private Boolean syncTtlToRedis = false;

        /**
         * Key命名空间（前缀）
         * 如果相统一缓存名前缀则可以使用
         */
        private String namespace = "";

        /**
         * Redis存储模式（generic | hash）
         * generic 则会使用String数据格式，且可以为每个KEY设置过期时间
         * hash 则会使用Hash模式，无法为每个单独item-key设置过期时间
         */
        private String storage = "generic";

        /**
         * Redis发布订阅（Pub/Sub）对应的channel名称
         */
        private String channel = "customize-j2cache";

        /**
         * Redis DB序号,默认与spring-data-redis配置一致
         */
        private Integer database = 0;


        public String getProviderClass() {
            return providerClass;
        }

        public void setProviderClass(String providerClass) {
            this.providerClass = providerClass;
        }

        public String getSerialization() {
            return serialization;
        }

        public void setSerialization(String serialization) {
            this.serialization = serialization;
        }

        public String getL2CacheSection() {
            return l2CacheSection;
        }

        public void setL2CacheSection(String l2CacheSection) {
            this.l2CacheSection = l2CacheSection;
        }

        public Boolean getSyncTtlToRedis() {
            return syncTtlToRedis;
        }

        public void setSyncTtlToRedis(Boolean syncTtlToRedis) {
            this.syncTtlToRedis = syncTtlToRedis;
        }

        public String getNamespace() {
            return namespace;
        }

        public void setNamespace(String namespace) {
            this.namespace = namespace;
        }

        public String getStorage() {
            return storage;
        }

        public void setStorage(String storage) {
            this.storage = storage;
        }

        public String getChannel() {
            return channel;
        }

        public void setChannel(String channel) {
            this.channel = channel;
        }

        public Integer getDatabase() {
            return database;
        }

        public void setDatabase(Integer database) {
            this.database = database;
        }

    }


    public Boolean getOpenSpringCache() {
        return openSpringCache;
    }

    public void setOpenSpringCache(Boolean openSpringCache) {
        this.openSpringCache = openSpringCache;
    }

    public String getCacheCleanMode() {
        return cacheCleanMode;
    }

    public void setCacheCleanMode(String cacheCleanMode) {
        this.cacheCleanMode = cacheCleanMode;
    }

    public boolean isAllowNullValues() {
        return allowNullValues;
    }

    public void setAllowNullValues(boolean allowNullValues) {
        this.allowNullValues = allowNullValues;
    }


    public boolean isL2CacheOpen() {
        return l2CacheOpen;
    }

    public void setL2CacheOpen(boolean l2CacheOpen) {
        this.l2CacheOpen = l2CacheOpen;
    }

    public String getBroadcast() {
        return broadcast;
    }

    public void setBroadcast(String broadcast) {
        this.broadcast = broadcast;
    }

    public MyLevel1Config getL1() {
        return l1;
    }

    public void setL1(MyLevel1Config l1) {
        this.l1 = l1;
    }

    public MyLevel2Config getL2() {
        return l2;
    }

    public void setL2(MyLevel2Config l2) {
        this.l2 = l2;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
